#include <llvm/Pass.h>
#include <llvm/IR/Instruction.h>
#include <llvm/IR/Instructions.h>
#include "llvm/Analysis/Dominators.h"
#include <map>
#include <set>

namespace llvm {
    ModulePass *createDINOVersioner ();
}

class DINOStoreAnalysis : public llvm::ModulePass {
    public:
        static char ID;
        DINOStoreAnalysis();
        virtual ~DINOStoreAnalysis();
        virtual const char *getPassName() const;

        typedef std::vector<llvm::Instruction *> InstList;
        typedef std::vector<llvm::GlobalVariable *> GlobalVarSet;

        void getNVVars (llvm::Function &F, GlobalVarSet &G);
        InstList *getNVStores (llvm::Function &F);
        InstList getTaskBoundaries (llvm::Instruction &I);

        // Utility functions
        bool isNVStore (llvm::Instruction &I);
        bool isTaskBoundary (llvm::Instruction &I);
        llvm::GlobalVariable *getVarFromStore (llvm::StoreInst &SI);

        virtual bool doInitialization (llvm::Module &M);
        virtual bool runOnModule (llvm::Module &M);
        virtual bool doFinalization (llvm::Module &M);
        virtual void getAnalysisUsage (llvm::AnalysisUsage &AU) const;

    private:
        std::map<llvm::StringRef, bool> GlobalNVness;
        std::map<llvm::Function *, GlobalVarSet> NVVars;
        std::map<llvm::Function *, InstList> NVStores;
};

class DINOVersioner : public llvm::ModulePass {
    public:
        static char ID;
        DINOVersioner ();
        virtual ~DINOVersioner ();
        virtual const char *getPassName() const;

        virtual bool doInitialization (llvm::Module &M);
        virtual bool runOnModule (llvm::Module &M);
        virtual bool doFinalization (llvm::Module &M);
        virtual void getAnalysisUsage (llvm::AnalysisUsage &AU) const;

    private:
        llvm::Function* verfn;
        llvm::DominatorTree *domTree;
};

extern const char *NVGlobalPrefix;
extern const char *DINOTaskBoundaryFunctionName;
extern const char *DINOVersionFunctionName;
extern const char *DINOPrefix;
